package com.sailing.xjpb.common.encrypt;


import com.sailing.xjpb.common.exception.ConvertException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;

import javax.crypto.Cipher;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * RSA加解密算法类
 *
 * @author FanHaiChao
 * createDate 2024/6/11 11:15
 */
public class RSA {

    private RSA() {
    }

    /**
     * RSA算法名称
     */
    private static final String ALGORITHMS = "RSA";
    /**
     * RSA算法模式
     */
    private static final String RSA_MODE = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";

    /**
     * 生成公钥，私钥
     *
     * @return 公钥和私钥
     */
    public static Pair<String, String> generatePublicPrivateKeys() {
        try {
            // KeyPairGenerator:秘钥对生成器对象
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHMS);
            // 生成密钥对
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            // 生成私钥
            PrivateKey privateKey = keyPair.getPrivate();
            // 生成公钥
            PublicKey publicKey = keyPair.getPublic();
            // 获取私销的字节数组
            byte[] privateKeyEncoded = privateKey.getEncoded();
            // 获取公销字节数组
            byte[] publicKeyEncoded = publicKey.getEncoded();
            // 使用base64进行编码
            String privateEncodeString = Base64.encodeBase64String(privateKeyEncoded);
            String publicEncodeString = Base64.encodeBase64String(publicKeyEncoded);
            return Pair.of(publicEncodeString, privateEncodeString);
            // 打印公钥和私钥
        } catch (Exception e) {
            throw new ConvertException("RSA获取公钥和私钥出错！", e);
        }
    }

    /**
     * RSA加密
     *
     * @param content      未加密的字符串
     * @param rsaPublicKey 公钥字符串
     * @return 加密后的密文
     */
    public static String encrypt(String content, String rsaPublicKey) {
        try {
            if (StringUtils.isBlank(content)) {
                return StringUtils.EMPTY;
            }
            byte[] publicKeyEncoded = Base64.decodeBase64(rsaPublicKey);
            // 创建key的工厂
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHMS);
            // 创建 已编码的公钥规格
            X509EncodedKeySpec encPubKeySpec = new X509EncodedKeySpec(publicKeyEncoded);
            // 获取指定算法的密钥工厂, 根据 已编码的公钥规格, 生成公钥对象
            PublicKey publicKey = keyFactory.generatePublic(encPubKeySpec);
            // 获取指定算法的密码器
            Cipher cipher = Cipher.getInstance(RSA_MODE);
            OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-1"),
                    PSource.PSpecified.DEFAULT);
            // 初始化密码器（公钥加密模型）
            cipher.init(Cipher.ENCRYPT_MODE, publicKey, oaepParams);
            // 加密数据, 返回加密后的密文
            byte[] cipherData = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
            // 采用base64算法进行转码,避免出现中文乱码
            return Base64.encodeBase64String(cipherData);
        } catch (Exception e) {
            throw new ConvertException("算法加密出错！", e);
        }
    }

    /**
     * RSA解密
     *
     * @param encodeEncryptStr 未解密的字符串
     * @param rsaPrivateKey    私钥字符串
     * @return 解密后的明文
     */
    public static String decrypt(String encodeEncryptStr, String rsaPrivateKey) {
        try {
            if (StringUtils.isBlank(encodeEncryptStr)) {
                return StringUtils.EMPTY;
            }
            byte[] privateKeyEncoded = Base64.decodeBase64(rsaPrivateKey);
            // 创建key的工厂
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHMS);
            // 创建 已编码的私钥规格
            PKCS8EncodedKeySpec encPriKeySpec = new PKCS8EncodedKeySpec(privateKeyEncoded);
            // 获取指定算法的密钥工厂, 根据 已编码的私钥规格, 生成私钥对象
            PrivateKey privateKey = keyFactory.generatePrivate(encPriKeySpec);
            // 获取指定算法的密码器
            Cipher cipher = Cipher.getInstance(RSA_MODE);
            OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-1"),
                    PSource.PSpecified.DEFAULT);
            // 初始化密码器（私钥解密模型）
            cipher.init(Cipher.DECRYPT_MODE, privateKey, oaepParams);
            // 解密数据, 返回解密后的明文
            byte[] plainData = cipher.doFinal(Base64.decodeBase64(encodeEncryptStr));
            // 采用base64算法进行转码,避免出现中文乱码
            return new String(plainData, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new ConvertException("算法解密出错！", e);
        }
    }

}
